package com.derbysoft.lowcostadapter.dswitch3.translate.impl;

import com.derbysoft.dswitch.dto.hotel.common.CustomerDTO;
import com.derbysoft.dswitch.dto.hotel.common.StayDateRangeDTO;
import com.derbysoft.dswitch.dto.hotel.common.TelephoneDTO;
import com.derbysoft.dswitch.dto.hotel.common.TransactionActionType;
import com.derbysoft.dswitch.dto.hotel.reservation.HotelReservationRQ;
import com.derbysoft.dswitch.dto.hotel.reservation.ReservationRoomStayDTO;
import com.derbysoft.dswitch.remote.hotel.dto.HotelReservationRequest;
import com.derbysoft.lowcostadapter.commons.dto.*;
import com.derbysoft.lowcostadapter.commons.exception.InvalidFieldException;
import com.derbysoft.lowcostadapter.commons.utils.DateTimeUtils;
import com.derbysoft.lowcostadapter.dswitch2.service.helper.Constant;
import com.derbysoft.lowcostadapter.dswitch3.translate.Translator;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Component;

import java.util.List;

/**
 * Created by: jason
 * Date: 2012-06-26
 */
@Component("ds3ReservationRQTranslator")
public class DSwitch3ReservationRQTranslator extends AbstractDSwitch3Translator
        implements Translator<HotelReservationRequest, Book, Void> {

    @Override
    public Book translate(HotelReservationRequest reservationRequest, Void aVoid) {
        Book book = new Book();
        book.setBookRequest(createBookRequest(reservationRequest));
        return book;
    }

    private BookRequest createBookRequest(HotelReservationRequest reservationRequest) {
        HotelReservationRQ reservationRQ = reservationRequest.getHotelReservationRQ();
        if (reservationRQ.getResActionType() != TransactionActionType.BOOK) {
            throw new InvalidFieldException("resActionType", reservationRQ.getResActionType().name());
        }
        BookRequest bookRequest = new BookRequest();
        bookRequest.setBookingDetails(createBookingDetails(reservationRQ));
        bookRequest.setLoginDetails(createLoginDetails(reservationRequest.getHeader().getSource()));
        return bookRequest;
    }

    private BookingDetailsInfo createBookingDetails(HotelReservationRQ hotelReservationRQ) {
        ReservationRoomStayDTO reservationRoomStayDTO = hotelReservationRQ.getHotelReservation().getRoomStaysList().get(0);
        BookingDetailsInfo bookingDetailsInfo = new BookingDetailsInfo();
        bookingDetailsInfo.setTradeReference(hotelReservationRQ.getErsp());
        bookingDetailsInfo.setPropertyID(Integer.parseInt(hotelReservationRQ.getHotelReservation().getHotelCode()));
        StayDateRangeDTO stayDateRange = reservationRoomStayDTO.getStayDateRange();
        bookingDetailsInfo.setArrivalDate(stayDateRange.getCheckin());
        bookingDetailsInfo.setDuration(DateTimeUtils.getIntervalDays(stayDateRange.getCheckin(), stayDateRange.getCheckout()));
        bookingDetailsInfo.setRoomBookings(createRoomBookings(hotelReservationRQ));

        CustomerDTO customerDTO = reservationRoomStayDTO.getGuestsList().get(0);
        if (StringUtils.isNotEmpty(customerDTO.getPersonName().getNameTitle())) {
            bookingDetailsInfo.setLeadGuestTitle(customerDTO.getPersonName().getNameTitle());
        } else {
            bookingDetailsInfo.setLeadGuestTitle(Constant.TITLE);
        }
        bookingDetailsInfo.setLeadGuestFirstName(customerDTO.getPersonName().getGivenName());
        bookingDetailsInfo.setLeadGuestLastName(customerDTO.getPersonName().getSurname());
        if (CollectionUtils.isNotEmpty(customerDTO.getAddressesList())) {
            bookingDetailsInfo.setLeadGuestAddress1(customerDTO.getAddressesList().get(0));
            if (customerDTO.getAddressesList().size() > 1) {
                bookingDetailsInfo.setLeadGuestAddress2(customerDTO.getAddressesList().get(1));
            }
        } else {
            bookingDetailsInfo.setLeadGuestAddress1(Constant.UNKNOWN);
        }
        bookingDetailsInfo.setLeadGuestTownCity(Constant.UNKNOWN);
        bookingDetailsInfo.setLeadGuestCounty(Constant.UNKNOWN);
        bookingDetailsInfo.setLeadGuestPostcode(Constant.UNKNOWN);
        bookingDetailsInfo.setLeadGuestPhone(findTelephone(customerDTO.getTelephonesList(), TelephoneDTO.PhoneTechType.VOICE));
        bookingDetailsInfo.setLeadGuestFax(findTelephone(customerDTO.getTelephonesList(), TelephoneDTO.PhoneTechType.FAX));
        bookingDetailsInfo.setLeadGuestEmail(createEmail(customerDTO.getEmailsList()));
        bookingDetailsInfo.setRequest(createRequest(reservationRoomStayDTO));
        return bookingDetailsInfo;
    }

    private String createRequest(ReservationRoomStayDTO reservationRoomStayDTO) {
        StringBuilder builder = new StringBuilder("");
        List<String> specialRequests = reservationRoomStayDTO.getSpecialRequestsList();
        if (CollectionUtils.isNotEmpty(specialRequests)) {
            for (String specialRequest : specialRequests) {
                builder.append(specialRequest).append(",");
            }
        }

        List<String> comments = reservationRoomStayDTO.getCommentsList();
        if (CollectionUtils.isNotEmpty(comments)) {
            for (String comment : comments) {
                builder.append(comment).append(",");
            }
        }

        return builder.toString();
    }

    private String createEmail(List<String> emails) {
        if (CollectionUtils.isNotEmpty(emails)) {
            return StringUtils.trimToNull(emails.get(0));
        }
        return BLANK;
    }

    private String findTelephone(List<TelephoneDTO> telephonesList, TelephoneDTO.PhoneTechType phoneTechType) {
        if (CollectionUtils.isNotEmpty(telephonesList)) {
            for (TelephoneDTO telephoneDTO : telephonesList) {
                if (telephoneDTO.getTechType() == phoneTechType) {
                    return telephoneDTO.getNumber();
                }
            }
        }
        return BLANK;
    }

    private ArrayOfRoomBooking createRoomBookings(HotelReservationRQ hotelReservationRQ) {
        ArrayOfRoomBooking arrayOfRoomBooking = new ArrayOfRoomBooking();
        ReservationRoomStayDTO reservationRoomStayDTO = hotelReservationRQ.getHotelReservation().getRoomStaysList().get(0);
        for (int roomIndex = 0; roomIndex < reservationRoomStayDTO.getNumberOfUnits(); roomIndex++) {
            arrayOfRoomBooking.getRoomBooking().add(
                    createRoomBooking(roomIndex, reservationRoomStayDTO.getGuestsList(), reservationRoomStayDTO));
        }
        return arrayOfRoomBooking;
    }

    private RoomBooking createRoomBooking(int roomIndex, List<CustomerDTO> guests,
                                          ReservationRoomStayDTO reservationRoomStayDTO) {
        RoomBooking roomBooking = new RoomBooking();
        roomBooking.setAdults(reservationRoomStayDTO.getAdultCount());
        roomBooking.setChildren(reservationRoomStayDTO.getChildCount());
        roomBooking.setPropertyRoomTypeID(Integer.valueOf(reservationRoomStayDTO.getRoomTypeCode()));
        roomBooking.setMealBasisID(Integer.valueOf(reservationRoomStayDTO.getRatePlanCode()));
        ArrayOfGuest arrayOfGuest = new ArrayOfGuest();
        int guestCount = roomBooking.getAdults() + roomBooking.getChildren();
        for (int guestIndex = 0; guestIndex < guestCount; guestIndex++) {
            int index = (roomIndex * guestCount + guestIndex) % guests.size();
            arrayOfGuest.getGuest().add(createGuest(guests.get(index), guestIndex < roomBooking.getAdults()));
        }
        roomBooking.setGuests(arrayOfGuest);
        return roomBooking;
    }

    private Guest createGuest(CustomerDTO customerDTO, boolean isAdult) {
        Guest guest = new Guest();
        guest.setType(isAdult ? Constant.ADULT : Constant.CHILD);
        if (StringUtils.isNotEmpty(customerDTO.getPersonName().getNameTitle())) {
            guest.setTitle(customerDTO.getPersonName().getNameTitle());
        } else {
            guest.setTitle(Constant.TITLE);
        }
        guest.setFirstName(customerDTO.getPersonName().getGivenName());
        guest.setLastName(customerDTO.getPersonName().getSurname());
        guest.setAge(isAdult ? 0 : 10);
        return guest;
    }
}
